package com.njtoyo.taxi.admin.service.business.driver.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njtoyo.taxi.admin.cache.PrimaryCachePutter;
import com.njtoyo.taxi.admin.library.Const;
import com.njtoyo.taxi.admin.library.common.Enum;
import com.njtoyo.taxi.admin.library.common.OperationRecordHelper;
import com.njtoyo.taxi.admin.library.common.util.CopyUtil;
import com.njtoyo.taxi.admin.library.taxi_service.TaxiService;
import com.njtoyo.taxi.admin.library.taxi_service.TaxiServiceResponse;
import com.njtoyo.taxi.admin.logic.business.CustomerLogic;
import com.njtoyo.taxi.admin.logic.business.TaxisLogic;
import com.njtoyo.taxi.admin.logic.business.UserLogic;
import com.njtoyo.taxi.admin.logic.business.driver.DriverLogic;
import com.njtoyo.taxi.admin.logic.driver.DriverAuditLogic;
import com.njtoyo.taxi.admin.mapper.master.entity.*;
import com.njtoyo.taxi.admin.mapper.master.enums.RecommendationFromCategoryPlatform;
import com.njtoyo.taxi.admin.mapper.master.enums.RecommendationPromoteChannel;
import com.njtoyo.taxi.admin.mapper.master.enums.RecommendationRelationPlatform;
import com.njtoyo.taxi.admin.mapper.master.enums.RideStateState;
import com.njtoyo.taxi.admin.mapper.master.mapper.*;
import com.njtoyo.taxi.admin.rest.export.driver.DriverListData;
import com.njtoyo.taxi.admin.rest.presenter.business.driver.*;
import com.njtoyo.taxi.admin.rest.presenter.platfrom.AdminUserIdentityPresenter;
import com.njtoyo.taxi.admin.rest.readfile.driver.DriverRegisterData;
import com.njtoyo.taxi.admin.rest.readfile.driver.DriverRegisterListener;
import com.njtoyo.taxi.admin.rest.readfile.driver.DriverSwitchTaxiData;
import com.njtoyo.taxi.admin.rest.readfile.driver.DriverSwitchTaxiListener;
import com.njtoyo.taxi.admin.rest.wrapper.business.canton.RegionUpdateWrapper;
import com.njtoyo.taxi.admin.rest.wrapper.business.driver.*;
import com.njtoyo.taxi.admin.service.business.driver.DriverService;
import com.njtoyo.taxi.entity.backend.AdminUser;
import com.taxi.entity.common.RestResult;
import com.taxi.entity.common.ResultEnum;
import org.nutz.lang.Strings;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

import static cn.hutool.core.util.ObjectUtil.isNotEmpty;
import static java.util.stream.Collectors.*;

@Service
public class DriverServiceImpl implements DriverService {
    @Autowired
    private DriverMapper driverMapper;
    @Autowired
    private PrimaryCachePutter primaryCachePutter;
    @Autowired
    private OperationRecordHelper operationRecordHelper;
    @Autowired
    private DriverLogic driverLogic;

    @Autowired
    private TaxiService taxiService;

    @Autowired
    private TaxiMapper taxiMapper;

    @Autowired
    private RideOrderMapper rideOrderMapper;

    @Autowired
    private CancellationOrderMapper cancellationOrderMapper;

    @Autowired
    private StreetRideOrderMapper streetRideOrderMapper;

    @Autowired
    private ScanRideOrderMapper scanRideOrderMapper;

    @Autowired
    private SimpleCallRideOrderMapper simpleCallRideOrderMapper;

    @Autowired
    private DriverMoneyDeductingMapper driverMoneyDeductingMapper;

    @Autowired
    private DriverWithdrawMapper driverWithdrawMapper;

    @Autowired
    private DriverRewardMapper driverRewardMapper;
    @Autowired
    private RecommendationMapper recommendationMapper;
    @Autowired
    private MemberMapper memberMapper;
    @Autowired
    private GeoCantonMapper geoCantonMapper;
    @Autowired
    private GeoDriverRegionMapper geoDriverRegionMapper;
    @Autowired
    private CompanyMapper companyMapper;

    @Autowired
    private MemberRebateMapper memberRebateMapper;

    @Autowired
    private UserLogic userLogic;

    @Autowired
    private RecommendationRelationshipMapper recommendationRelationshipMapper;

    @Autowired
    private DriverAuditLogic driverAuditLogic;

    @Autowired
    private DriverRecommendTaskCompletionMapper driverRecommendTaskCompletionMapper;

    @Autowired
    private CustomerLogic customerLogic;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private CustomerInfoMapper customerInfoMapper;

    @Autowired
    private RideMapper rideMapper;
    @Autowired
    private TaxiLastLocateMapper taxiLastLocateMapper;
    @Autowired
    private DriverExtraInformationMapper driverExtraInformationMapper;
    @Autowired
    private DriverDeviceRelationshipMapper driverDeviceRelationshipMapper;
    @Autowired
    @Qualifier(value = Const.PRIMARY_CACHE_TEMPLATE)
    private RedisTemplate redisTemplate;
    @Autowired
    private TaxisLogic taxisLogic;
    @Autowired
    private GeoCantonAreaMapper geoCantonAreaMapper;
    @Autowired
    private DriverAutomaticOpenTimeLogMapper driverAutomaticOpenTimeLogMapper;
    @Autowired
    private DriverTaxiRelationMapper driverTaxiRelationMapper;
    @Autowired
    private LifeTableMapper lifeTableMapper;
    @Autowired
    private DriverBankingMapper driverBankingMapper;

    /**
     * 司机列表
     *
     * @param adminUser
     * @param wrapper
     * @return
     */
    @Override
    public RestResult<Page<DriverListPresenter>> getList(AdminUser adminUser, DriverQueryWrapper wrapper) {
        AdminUserIdentityPresenter identity = (AdminUserIdentityPresenter) adminUser.getIdentity();
        switch (adminUser.getAccountType()) {
            case canton:
                wrapper.setCantonIds(identity.getCantonIds());
                break;
            case company:
                if (isNotEmpty(wrapper.getCompanyId())) {
                    wrapper.getCompanyId().addAll(identity.getCompanyIds());
                } else {
                    wrapper.setCompanyId(identity.getCompanyIds());
                }
        }
        Page<DriverListPresenter> page = driverMapper.selectDriverPageList(wrapper);
        List<DriverListPresenter> list = page.getRecords();
        List<Long> ids = list.stream()
                .map(DriverListPresenter::getId)
                .collect(toList());
        List<Long> cantonIds = list.stream()
                .map(DriverListPresenter::getCantonId)
                .collect(toList());
        List<Long> driverRrgionIds = list.stream()
                .map(DriverListPresenter::getDriverRegionId)
                .collect(toList());
        List<Long> taxiIds = list.stream()
                .map(DriverListPresenter::getTaxiId)
                .collect(toList());
        //验证是否存在数据
        if (ids.size() == 0) {
            return RestResult.success(page);
        }
        //车辆信息O
        List<Taxi> taxiList = taxiMapper.selectList(Wrappers.<Taxi>lambdaQuery()
                .in(Taxi::getId, taxiIds));
        //公司信息
        List<Company> companyList = null;
        if (isNotEmpty(taxiList)) {
            List<Long> companyIds = taxiList.stream().map(Taxi::getCompanyId).collect(toList());
            companyList = companyMapper.selectList(Wrappers.<Company>lambdaQuery()
                    .in(Company::getId, companyIds));
        }
        //会员信息
        QueryWrapper<Member> memberQueryWrapper = new QueryWrapper<>();
        memberQueryWrapper.select("id", "ref_id", "level");
        memberQueryWrapper.eq("category", 0);
        memberQueryWrapper.in("ref_id", ids);
        List<Member> memberList = memberMapper.selectList(memberQueryWrapper);

        //行政区信息
        QueryWrapper<GeoCanton> cantonWrapper = new QueryWrapper<>();
        cantonWrapper.select("id", "name");
        cantonWrapper.in("id", cantonIds);
        List<Map<String, Object>> geoCantons = geoCantonMapper.selectMaps(cantonWrapper);
        Map<Long, String> cantonMap = geoCantons.stream().collect(Collectors.toMap(i -> Long.valueOf(i.get("id").toString()), i -> i.get("name").toString()));

        //司机运营区
        QueryWrapper<GeoDriverRegion> driverRegionWrapper = new QueryWrapper<>();
        driverRegionWrapper.select("id", "name");
        driverRegionWrapper.in("id", driverRrgionIds);
        List<Map<String, Object>> geoDriverRegions = geoDriverRegionMapper.selectMaps(driverRegionWrapper);
        Map<Long, String> driverRegionMap = geoDriverRegions.stream().collect(Collectors.toMap(i -> Long.valueOf(i.get("id").toString()), i -> i.get("name").toString()));

        for (DriverListPresenter result : list) {
            DriverExtraInformation extraInformation = driverExtraInformationMapper.getByDriverId(result.getId());
            if (ObjectUtil.isNotNull(extraInformation) && StrUtil.isNotBlank(extraInformation.getDeviceAutoInfo())) {
                JSONObject jsonObject = JSON.parseObject(extraInformation.getDeviceAutoInfo());
                result.setVersion(jsonObject.getString("v"));
            }
            result.setExtraInfo(extraInformation);

            result.setCantonName(cantonMap.getOrDefault(result.getCantonId(), null));
            result.setDriverRegionName(driverRegionMap.getOrDefault(result.getDriverRegionId(), null));
            memberList.stream().filter(m -> m.getRefId().equals(result.getId())).forEach(m -> {
                result.setMemberId(m.getId());
                result.setMemberLevel(m.getLevel());
            });
            taxiList.stream().filter(taxi -> result.getTaxiId().equals(taxi.getId())).forEach(taxi -> {
                result.setTaxiPlatNumber(taxi.getPlateNumber());
                result.setCompanyId(taxi.getCompanyId());
            });
            companyList.stream().filter(company -> ObjectUtil.isNotNull(company) && ObjectUtil.isNotNull(result.getCompanyId()) &&
                    result.getCompanyId().equals(company.getId())).forEach(company ->
                    result.setCompanyName(company.getName()));

            DriverDeviceRelationship driverDeviceRelationship = driverDeviceRelationshipMapper.selectOne(Wrappers.<DriverDeviceRelationship>lambdaQuery()
                    .eq(DriverDeviceRelationship::getState, 1)
                    .eq(DriverDeviceRelationship::getDriverId, result.getId()));
            if (ObjectUtil.isNotNull(driverDeviceRelationship)) {
                result.setLoginTime(driverDeviceRelationship.getUpdatedAt());
            }
            Taxi taxi = taxiMapper.selectById(result.getTaxiId());
            if (ObjectUtil.isNotNull(taxi)) {
                result.setUpdatedAt(taxi.getUpdatedAt());
                //最新坐标

                TaxiLastLocate taxiLastLocate = taxiLastLocateMapper.selectOne(Wrappers.<TaxiLastLocate>lambdaQuery()
                        .eq(TaxiLastLocate::getTaxiId, taxi.getId())
                        .orderByDesc(TaxiLastLocate::getUpdatedAt)
                        .last("LIMIT 1"));
                if (ObjectUtil.isNotNull(taxiLastLocate) && ObjectUtil.isNotNull(taxiLastLocate.getGpsTime())) {
                    result.setGpsTime(DateUtil.date(taxiLastLocate.getGpsTime()));
                }
            }

        }
        return RestResult.success(page);
    }

    /**
     * 司机详情
     *
     * @param id
     * @return
     */
    @Override
    public RestResult<DriverDetailsPresenter> driverDetails(Long id) {
        Driver driver = driverMapper.selectById(id);
        if (ObjectUtils.isEmpty(driver)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }
        DriverDetailsPresenter driverDetailsPresenter = new DriverDetailsPresenter();
        BeanUtils.copyProperties(driver, driverDetailsPresenter);

        DriverExtraInformation extraDriver = driverExtraInformationMapper.getByDriverId(id);
        driverDetailsPresenter.setExtraInfo(extraDriver);
        if (Objects.nonNull(extraDriver)) {
            driverDetailsPresenter.setVehicleLicenceNumber(extraDriver.getVehicleLicenceNumber());
            driverDetailsPresenter.setQualificationCertificateNumber(extraDriver.getQualificationCertificateNumber());
            driverDetailsPresenter.setIdentityNumber(extraDriver.getIdentityNumber());
        }

        //会员信息
        QueryWrapper<Member> memberQueryWrapper = new QueryWrapper<>();
        memberQueryWrapper.eq("category", 0);
        memberQueryWrapper.eq("ref_id", id);
        Member member = memberMapper.selectOne(memberQueryWrapper);
        if (!ObjectUtils.isEmpty(member)) {
            driverDetailsPresenter.setMemberLevel(member.getLevel());
            driverDetailsPresenter.setState(member.getState());
            driverDetailsPresenter.setPoint(member.getPoint());
            driverDetailsPresenter.setValidPoint(member.getValidPoint());
        }

        driverDetailsPresenter.setLoginOnce(Strings.isNotBlank(driver.getDeviceInfo()));
        Long cantonId = driverDetailsPresenter.getCantonId();
        Long driverRegionId = driverDetailsPresenter.getDriverRegionId();
        Long taxiId = driverDetailsPresenter.getTaxiId();
        //地区
        QueryWrapper<GeoCanton> cantonWrapper = new QueryWrapper<>();
        cantonWrapper.select("id", "name");
        cantonWrapper.eq("id", cantonId);
        GeoCanton geoCanton = geoCantonMapper.selectOne(cantonWrapper);
        driverDetailsPresenter.setCantonName(geoCanton.getName());
        //司机运营区
        QueryWrapper<GeoDriverRegion> driverRegionQueryWrapper = new QueryWrapper<>();
        driverRegionQueryWrapper.select("id", "name");
        driverRegionQueryWrapper.eq("id", driverRegionId);
        GeoDriverRegion geoDriverRegion = geoDriverRegionMapper.selectOne(driverRegionQueryWrapper);
        driverDetailsPresenter.setDriverRegionName(geoDriverRegion.getName());
        //车牌号
        QueryWrapper<Taxi> taxiQueryWrapper = new QueryWrapper<>();
        taxiQueryWrapper.select("id,plate_number", "company_id");
        taxiQueryWrapper.eq("id", taxiId);
        Taxi taxi = taxiMapper.selectOne(taxiQueryWrapper);
        driverDetailsPresenter.setTaxiPlatNumber(taxi.getPlateNumber());
        //公司
        QueryWrapper<Company> companyQueryWrapper = new QueryWrapper<>();
        companyQueryWrapper.select("name");
        companyQueryWrapper.eq("id", taxi.getCompanyId());
        Company company = companyMapper.selectOne(companyQueryWrapper);
        driverDetailsPresenter.setCompanyName(company.getName());
        //最新坐标
        TaxiLastLocate taxiLastLocate = taxiLastLocateMapper.selectOne(Wrappers.<TaxiLastLocate>lambdaQuery()
                .eq(TaxiLastLocate::getTaxiId, taxi.getId())
                .orderByDesc(TaxiLastLocate::getUpdatedAt)
                .last("LIMIT 1"));
        if (ObjectUtil.isNotNull(taxiLastLocate) && ObjectUtil.isNotNull(taxiLastLocate.getGpsTime())) {
            driverDetailsPresenter.setGpsTime(DateUtil.date(taxiLastLocate.getGpsTime()).toString());
        }
        return RestResult.success(driverDetailsPresenter);
    }


    /**
     * 仅修改司机姓名
     *
     * @param updateDriverNameWrapper
     * @return
     */
    @Override
    public RestResult updateDriverInformation(Long id, UpdateDriverInformationWrapper updateDriverNameWrapper) {
        Driver driver = driverMapper.selectById(id);
        if (ObjectUtils.isEmpty(driver)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }
        DriverExtraInformation driverExtraInformation = driverExtraInformationMapper.selectOne(Wrappers.<DriverExtraInformation>lambdaQuery()
                .eq(DriverExtraInformation::getIdentityNumber, updateDriverNameWrapper.getIdentityNumber())
                .not(i -> i.eq(DriverExtraInformation::getDriverId, id)));
        if (ObjectUtil.isNotNull(driverExtraInformation)) {
            return RestResult.failed("身份证号已存在,不能重复添加！");
        }
        String oldName = driver.getName();
        String newName = updateDriverNameWrapper.getName();
        new LambdaUpdateChainWrapper<>(driverMapper)
                .eq(Driver::getId, id)
                .set(Driver::getName, newName)
                .update();
        DriverExtraInformation extraInfo = driverExtraInformationMapper.getByDriverId(id);
        if (Objects.isNull(extraInfo)) {
            extraInfo = new DriverExtraInformation();
            extraInfo.setDriverId(id)
                    .setIdentityNumber(StrUtil.trim(updateDriverNameWrapper.getIdentityNumber()))
                    .setQualificationCertificateNumber(updateDriverNameWrapper.getQualificationCertificateNumber());
            driverExtraInformationMapper.insert(extraInfo);
        } else {
            new LambdaUpdateChainWrapper<>(driverExtraInformationMapper)
                    .eq(DriverExtraInformation::getId, extraInfo.getId())
                    .set(Strings.isNotBlank(updateDriverNameWrapper.getIdentityNumber()), DriverExtraInformation::getIdentityNumber, updateDriverNameWrapper.getIdentityNumber())
                    .set(Strings.isNotBlank(updateDriverNameWrapper.getQualificationCertificateNumber()), DriverExtraInformation::getQualificationCertificateNumber, updateDriverNameWrapper.getQualificationCertificateNumber())
                    .update();
        }
        primaryCachePutter.deleteDriverCacheById(id);
        operationRecordHelper.addBusinessLog(String.format("修改了司机 [%s] 信息", driver.getId()));
        return RestResult.success();
    }

    /**
     * 司机换车牌号
     *
     * @param id
     * @param updateDriverNameWrapper
     * @return
     */
    @Override
    public RestResult updatePlateNumber(Long id, UpdatePlateNumberWrapper updateDriverNameWrapper) {
        Driver driver = driverMapper.selectById(id);
        if (driver.getInService()) {
            return RestResult.failed("司机正在出车中,不能更换车牌号");
        }
        Long taxiId = updateDriverNameWrapper.getTaxiId();
        try {
            driverLogic.switchTaxi(id, taxiId);
            redisTemplate.delete("driver:id:" + id);
            redisTemplate.delete("driver:info:" + id);
            redisTemplate.delete("consumer:driver:mobile:" + driver.getMobileNumber());
        } catch (Exception e) {
            return RestResult.failed(e.getMessage());
        }
        Driver updateDriver = new Driver();
        updateDriver.setId(id);
        updateDriver.setIsLeave(false);
        driverMapper.updateById(updateDriver);
        driverTaxiRelationMapper.delete(Wrappers.<DriverTaxiRelation>lambdaQuery()
                .eq(DriverTaxiRelation::getDriverId, id)
                .eq(DriverTaxiRelation::getTaxiId, taxiId));

        operationRecordHelper.addBusinessLog(String.format("将司机 [%d] 的车牌号换成了 %s ", id, taxiId));
        return RestResult.success();
    }

    @Override
    public RestResult<List<DriverQueryLikeListPresenter>> getListLike(DriverLikeQueryWrapper wrapper) {
        // 判断是否为手机号
        List<Driver> list = null;
        if (this.isPhoneNum(wrapper.getSearch())) {
            list = new LambdaQueryChainWrapper<>(driverMapper)
                    .select(Driver::getId, Driver::getName, Driver::getMobileNumber)
                    .eq(Driver::getMobileNumber, wrapper.getSearch())
                    .list();
        } else {
            // 先查一下
            list = new LambdaQueryChainWrapper<>(driverMapper)
                    .select(Driver::getId, Driver::getName, Driver::getMobileNumber)
                    .eq(Driver::getName, wrapper.getSearch())
                    .last("limit 30")
                    .list();

            if (list.size() < 10) {
                List<Driver> like = new LambdaQueryChainWrapper<>(driverMapper)
                        .select(Driver::getId, Driver::getName, Driver::getMobileNumber)
                        .ne(Driver::getName, wrapper.getSearch())
                        .like(Driver::getName, wrapper.getSearch())
                        .last(String.format("limit %d", 10 - list.size()))
                        .list();

                list.addAll(like);
            }
        }

        List<DriverQueryLikeListPresenter> res = CopyUtil.copyList(list, DriverQueryLikeListPresenter.class);
        return RestResult.success(res);
    }

    private Boolean isPhoneNum(String content) {
        return ReUtil.isMatch("^1[0-9]\\d{9}$", content);
    }

    @Override
    public RestResult<List<DriverQueryRideClickFarmingListPresenter>> getRideClickFarmingList(RideClickFarmingQueryWrapper wrapper) {
        List<DriverQueryRideClickFarmingListPresenter> result = this.getRideClickFarmingDataList(wrapper);

        return RestResult.success(result);
    }

    private List<DriverQueryRideClickFarmingListPresenter> getRideClickFarmingDataList(RideClickFarmingQueryWrapper wrapper) {
        // rideCount
        GetRideClickFarmingDto rideCountQuery = new GetRideClickFarmingDto();
        rideCountQuery.setHavingCount(wrapper.getRideCountThreshold());
        rideCountQuery.setStartDate(DateUtil.beginOfDay(wrapper.getStartDate()));
        rideCountQuery.setEndDate(DateUtil.endOfDay(wrapper.getEndDate()));

        List<DriverQueryRideClickFarmingDto> rideCountRes = rideOrderMapper.getRideOrAmountCountForRideClickFarming(rideCountQuery);

        // rideAmountCountQuery
        GetRideClickFarmingDto rideAmountCountQuery = new GetRideClickFarmingDto();
        rideAmountCountQuery.setAmountCondition(wrapper.getAmountCondition());
        rideAmountCountQuery.setHavingCount(wrapper.getAmountConditionalRideCountThreshold());
        rideAmountCountQuery.setStartDate(DateUtil.beginOfDay(wrapper.getStartDate()));
        rideAmountCountQuery.setEndDate(DateUtil.endOfDay(wrapper.getEndDate()));

        List<DriverQueryRideClickFarmingDto> rideAmountCountQueryRes = rideOrderMapper.getRideOrAmountCountForRideClickFarming(rideAmountCountQuery);

        List<Long> driverIds = new ArrayList<>();
        List<Long> rideCountDriverIds = rideCountRes.stream().map(DriverQueryRideClickFarmingDto::getDriverId).collect(Collectors.toList());
        List<Long> rideAmountCountDriverIds = rideAmountCountQueryRes.stream().map(DriverQueryRideClickFarmingDto::getDriverId).collect(Collectors.toList());

        // driverIds
        if (isNotEmpty(rideCountDriverIds)) {
            driverIds.addAll(rideCountDriverIds);
        }

        if (isNotEmpty(rideAmountCountDriverIds)) {
            driverIds.addAll(rideAmountCountDriverIds);
        }

        if (ObjectUtil.isEmpty(driverIds)) {
            return new ArrayList<>();
        }

        // 去重
        List<Long> driverIdsUnique = driverIds.stream().distinct().collect(Collectors.toList());
        DriverQueryWrapper driverQueryWrapper = new DriverQueryWrapper(1L, 2000L);
        driverQueryWrapper.setIds(driverIdsUnique);

        Page<DriverListPresenter> driverList = driverMapper.selectDriverPageList(driverQueryWrapper);

        List<DriverQueryRideClickFarmingListPresenter> result = CopyUtil.copyList(driverList.getRecords(), DriverQueryRideClickFarmingListPresenter.class);

        List<DriverListPresenter> driverInfoList = driverMapper.getDriverInfoByIds(driverIds);
        Map<Long, DriverListPresenter> driverInfoMap = driverInfoList.stream().collect(toMap(DriverListPresenter::getId, e -> e));
        for (DriverQueryRideClickFarmingListPresenter driver : result) {
            DriverListPresenter driverInfo = driverInfoMap.get(driver.getId());
            if (Objects.nonNull(driverInfo)) {
                driver.setTaxiPlatNumber(driverInfo.getTaxiPlatNumber());
                driver.setCompanyName(driverInfo.getCompanyName());
                driver.setCantonName(driverInfo.getCantonName());
                driver.setQualificationCertificateNumber(driverInfo.getQualificationCertificateNumber());
            }
            Optional<DriverQueryRideClickFarmingDto> firstRideCount = rideCountRes.stream().filter(i -> i.getDriverId().equals(driver.getId())).findFirst();
            firstRideCount.ifPresent(driverQueryRideClickFarmingDto -> driver.setRideCount(driverQueryRideClickFarmingDto.getCount()));

            Optional<DriverQueryRideClickFarmingDto> firstRideAmountCount = rideAmountCountQueryRes.stream().filter(i -> i.getDriverId().equals(driver.getId())).findFirst();
            firstRideAmountCount.ifPresent(driverQueryRideClickFarmingDto -> driver.setAmountConditionRideCount(driverQueryRideClickFarmingDto.getCount()));
        }

        return result;
    }

    @Override
    public void rideClickFarmingExport(RideClickFarmingQueryWrapper wrapper, HttpServletResponse response) throws IOException {
        List<DriverQueryRideClickFarmingListPresenter> result = this.getRideClickFarmingDataList(wrapper);

        String fileName = URLEncoder.encode("刷单风控", "UTF-8").replaceAll("\\+", "%20");
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), DriverQueryRideClickFarmingListPresenter.class)
                .sheet(0)
                .doWrite(result);
    }

    /**
     * 司机换手机号
     *
     * @param id
     * @param updatePhoneNumberWrapper
     * @return
     */
    @Override
    public RestResult updatePhoneNumber(Long id, UpdatePhoneNumberWrapper updatePhoneNumberWrapper) {
        Driver driver = driverMapper.selectById(id);
        if (ObjectUtils.isEmpty(driver)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }
        String oldMobileNumber = driver.getMobileNumber();
        String newMobileNumber = updatePhoneNumberWrapper.getMobileNumber();
        if (oldMobileNumber.equals(newMobileNumber)) {
            return RestResult.failed("原手机号不能相同");
        }
        String driverMobileNumber = driverMapper.selectMobileNumber(newMobileNumber);
        if (driverMobileNumber != null) {
            return RestResult.failed("手机号已经被他人注册");
        }
        new LambdaUpdateChainWrapper<>(driverMapper)
                .eq(Driver::getId, id)
                .set(Driver::getMobileNumber, newMobileNumber)
                .set(Driver::getPassword, SecureUtil.md5(newMobileNumber.substring(5) + "@yd"))
                .update();
        primaryCachePutter.deleteDriverCacheById(id);
        primaryCachePutter.deleteDriverMobile(oldMobileNumber);
        primaryCachePutter.deleteNoneExist();
        operationRecordHelper.addBusinessLog(String.format("将司机 [%d] 的手机号由 %s -> %s ", id, driver.getMobileNumber(),
                newMobileNumber));
        return RestResult.success();
    }


    /**
     * 司机重置密码
     *
     * @param id
     * @return
     */
    @Override
    public RestResult updatePassword(Long id) {
        Driver driver = driverMapper.selectById(id);
        if (ObjectUtils.isEmpty(driver)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }
        //将密码重新设置为手机号后六位并进行md5 加密，
        String mobileNumber = driver.getMobileNumber();
        if (ObjectUtils.isEmpty(mobileNumber)) {
            return RestResult.failed("请先绑定手机号");
        }
        String mobile = mobileNumber.substring(5) + "@yd";
        String md5 = DigestUtil.md5Hex("123456");

        new LambdaUpdateChainWrapper<>(driverMapper)
                .eq(Driver::getId, id)
                .set(Driver::getPassword, md5)
                .update();
        //清除司机id缓存，记录操作日志
        primaryCachePutter.deleteDriverCacheById(id);
        //清除密码错误锁定
        primaryCachePutter.deletePwdLock(mobileNumber);
        operationRecordHelper.addBusinessLog(String.format("重置了司机 [%d] 的密码", driver.getId()));
        return RestResult.success();
    }

    /**
     * 司机批量清除缓存
     *
     * @param
     * @return
     */
    @Override
    public RestResult deleteCache(DeleteCaheWrapper wrapper) {
        List<Long> ids = wrapper.getIds();
        if (ObjectUtils.isEmpty(ids)) {
            return RestResult.failed("清添加司机ID");
        }
        List<Driver> drivers = driverMapper.selectBatchClearCache(ids);
        if (!ObjectUtils.isEmpty(drivers)) {
            for (Driver d : drivers) {
                primaryCachePutter.deleteDriverCacheById(d.getId());
                primaryCachePutter.deleteDriverTodayIncome(d.getId());
                primaryCachePutter.deleteDriverMobile(d.getMobileNumber());
                primaryCachePutter.deleteDriverInfo(d.getId());
            }
        }
        return RestResult.success();
    }

    /**
     * 通过Excel司机批量换车牌
     *
     * @param
     * @return
     */
    @Override
    public RestResult updateSwitchTaxis(MultipartFile file) throws IOException {
        DriverSwitchTaxiListener listener = new DriverSwitchTaxiListener(driverLogic);
        EasyExcel.read(file.getInputStream(), DriverSwitchTaxiData.class, listener).sheet().doRead();
        return RestResult.success(listener.getResult());
    }

    /**
     * 批量注册
     *
     * @param file
     * @param wrapper
     * @return
     * @throws IOException
     */
    @Override
    public RestResult batchRegister(MultipartFile file, DriverBatchRegisterWrapper wrapper) throws IOException {
        DriverRegisterListener listener = new DriverRegisterListener(driverLogic, wrapper);
        EasyExcel.read(file.getInputStream(), DriverRegisterData.class, listener).sheet().doRead();
        List<Driver> successResult = listener.getResult().getSuccessResult();
        for (Driver d : successResult) {
            primaryCachePutter.deleteDriverMobile(d.getMobileNumber());
            operationRecordHelper.addBusinessLog(String.format("批量注册了司机 [%d] 的信息", d.getId()));
        }
        return RestResult.success(listener.getResult());
    }

    /**
     * 注册司机
     *
     * @param wrapper
     * @return
     */
    @Override
    public RestResult register(DriverRegisterWrapper wrapper) {
        try {
            primaryCachePutter.deleteDriverMobile(wrapper.getMobileNumber());
            Driver register = driverLogic.register(wrapper);
            operationRecordHelper.addBusinessLog(String.format("注册了司机 [%d] 的信息", register.getId()));
        } catch (Exception e) {
            return RestResult.failed(e.getMessage());
        }
        return RestResult.success();
    }

    /**
     * 司机离职
     *
     * @param id
     * @param leaveWrapper
     * @return
     */
    @Override
    public RestResult leave(Long id, LeaveDateWrapper leaveWrapper) {
        Date leaveTimes = leaveWrapper.getLeaveTime();
        //限制离职时间不超过今天
        Date date = new Date();
        if (leaveTimes.after(date)) {
            return RestResult.failed("离职时间不能超过今天");
        }
        Driver driver = driverMapper.selectById(id);
        if (ObjectUtils.isEmpty(driver)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }
        if (driver.getIsLeave()) {
            return RestResult.failed("司机已经离职");
        }
        Boolean inService = driver.getInService();
        if (ObjectUtils.isEmpty(inService) || inService) {
            return RestResult.failed("司机正在服务中");
        }
        String mobileNumber = driver.getMobileNumber();
        new LambdaUpdateChainWrapper<>(driverMapper)
                .eq(Driver::getId, id)
                .set(Driver::getIsLeave, true)
                .set(Driver::getIsActive, false)
                .set(Driver::getLeaveTime, leaveTimes)
                .set(Driver::getRefreshToken, null)
                .update();
        //清除缓存
        primaryCachePutter.deleteCustomerById(id);
        primaryCachePutter.deleteCustomerByMobile(mobileNumber);
        primaryCachePutter.deleteDriverTodayIncome(id);
        taxiService.updateDriverStateNotice(driver.getId(), Enum.DriverState.left);
        operationRecordHelper.addBusinessLog(String.format("司机 [%d] 离职了", id));
        //通知消息
        if (!driver.getIsActive()) {
            taxiService.updateDriverStateNotice(driver.getId(), Enum.DriverState.left);
        }
        return RestResult.success();
    }

    @Override
    public RestResult<?> unleave(Long id) {
        Driver driver = driverMapper.selectById(id);
        if (ObjectUtils.isEmpty(driver)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }
        if (!driver.getIsLeave()) {
            return RestResult.failed("司机未离职");
        }
        String mobileNumber = driver.getMobileNumber();
        new LambdaUpdateChainWrapper<>(driverMapper)
                .eq(Driver::getId, id)
                .set(Driver::getIsLeave, false)
                .set(Driver::getIsActive, true)
                .set(Driver::getLeaveTime, null)
                .update();
        //清除缓存
        primaryCachePutter.deleteCustomerById(id);
        primaryCachePutter.deleteCustomerByMobile(mobileNumber);
        primaryCachePutter.deleteDriverTodayIncome(id);
        taxiService.updateDriverStateNotice(driver.getId(), Enum.DriverState.left);
        operationRecordHelper.addBusinessLog(String.format("司机 [%d] 重新入职了", id));
        return RestResult.success();
    }

    /**
     * 司机Excel导出
     *
     * @param wrapper
     * @param response
     * @throws IOException
     */
    @Override
    public void downloadDriver(DriverExportWrapper wrapper, HttpServletResponse response) throws IOException {
        List<DriverListData> records = driverMapper.selectDriverList(wrapper);
        List<Long> ids = records.stream()
                .map(DriverListData::getId)
                .collect(toList());
        List<Long> cantonIds = records.stream()
                .map(DriverListData::getCantonId)
                .distinct()
                .collect(toList());
        List<Long> driverRegionIds = records.stream()
                .map(DriverListData::getDriverRegionId)
                .distinct()
                .collect(toList());
        //验证是否存在数据
        if (ids.size() != 0) {
            //行政区信息
            QueryWrapper<GeoCanton> cantonWrapper = new QueryWrapper<>();
            cantonWrapper.select("id", "name");
            cantonWrapper.in("id", cantonIds);
            List<GeoCanton> geoCantons = geoCantonMapper.selectList(cantonWrapper);
            //司机运营区
            QueryWrapper<GeoDriverRegion> driverRegionWrapper = new QueryWrapper<>();
            driverRegionWrapper.select("id", "name");
            driverRegionWrapper.in("id", driverRegionIds);
            List<GeoDriverRegion> geoDriverRegions = geoDriverRegionMapper.selectList(driverRegionWrapper);
            for (DriverListData e : records) {
                Long id = e.getId();
                Long cantonId = e.getCantonId();
                Long driverRegionId = e.getDriverRegionId();
                //行政区信息
                for (GeoCanton c : geoCantons) {
                    if (c.getId().equals(cantonId)) {
                        e.setCantonName(c.getName());
                    }
                }
                //司机运营区
                for (GeoDriverRegion c : geoDriverRegions) {
                    if (c.getId().equals(driverRegionId)) {
                        e.setDriverRegionName(c.getName());
                    }
                }
            }
        }
        String fileName = URLEncoder.encode("司机信息", "UTF-8").replaceAll("\\+", "%20");
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

        EasyExcel.write(response.getOutputStream(), DriverListData.class)
                .sheet(0)
                .doWrite(records);
    }

    /**
     * 司机批量解封号
     *
     * @return
     */
    @Override
    public RestResult batchIsBlock(DriverBatchUnblockWrapper wrapper) {
        new LambdaUpdateChainWrapper<>(driverMapper)
                .in(Driver::getId, wrapper.getIds())
                .set(Driver::getIsActive, wrapper.getIsActive())
                .set(Driver::getBanReason, wrapper.getBanReason())
                .set(Driver::getRefreshToken, null)
                .update();
        List<Driver> drivers = driverMapper.selectBatchIsBlock(wrapper.getIds());
        for (Driver driver : drivers) {
            primaryCachePutter.deleteDriverCacheById(driver.getId());
            primaryCachePutter.deleteDriverMobile(driver.getMobileNumber());
            // 通知消息
            if (!wrapper.getIsActive()) {
                taxiService.updateDriverStateNotice(driver.getId(), Enum.DriverState.frozen);
            }
            operationRecordHelper.addBusinessLog(String.format("账号司机 [%d] 的解封号状态改为 %s", driver.getId(), driver.getIsActive()));
        }
        return RestResult.success();
    }

    @Override
    public RestResult<DriverServiceStatePresenter> getServiceState(Long id) {
        Driver driver = driverMapper.selectById(id);
        if (Objects.isNull(driver)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }
        DriverServiceStatePresenter res = new DriverServiceStatePresenter();

        // 获取车俩信息
        Taxi taxi = taxiMapper.selectById(driver.getTaxiId());
        res.setTaxi(CopyUtil.copy(taxi, DriverServiceStatePresenter.Taxi.class));
        // 获取绑定司机信息
        List<Driver> drivers = driverMapper.selectList(new QueryWrapper<Driver>().eq("taxi_id", driver.getTaxiId()));
        res.setDriver(CopyUtil.copyList(drivers, DriverServiceStatePresenter.Driver.class));

        return RestResult.success(res);
    }

    @Override
    public RestResult setOffline(Long id) {
        Driver driver = driverMapper.selectById(id);
        if (Objects.isNull(driver)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }
        if (!driver.getInService()) {
            return RestResult.failed("司机已收车");
        }
        driverLogic.setOffline(driver);
        operationRecordHelper.addBusinessLog(String.format("强制司机收车 [%s]", id));
        return RestResult.success();
    }

    @Override
    public RestResult<DriverAccountPresenter> getAccount(Long id) {
        Driver driver = driverMapper.selectById(id);
        if (Objects.isNull(driver)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }


        DriverAccountPresenter res = new DriverAccountPresenter();

        res.setRiderOrder(rideOrderMapper.computeDriverBalance(id)); // 行程订单收入
        res.setRideCancellationOrder(cancellationOrderMapper.computeDriverBalance(id)); // 空驶费收入
        res.setStreetRideOrder(streetRideOrderMapper.computeDriverBalance(id)); // 街边收款收入
        res.setScanRideOrder(scanRideOrderMapper.computeDriverBalance(id)); // 扫码收款
        res.setSimpleRideOrder(simpleCallRideOrderMapper.computeDriverBalance(id)); //一键叫车
        res.setDeducting(driverMoneyDeductingMapper.computeDriverBalance(id)); // 平台扣款
        res.setWithdrawDone(driverWithdrawMapper.selectDoneAmount(id)); //已提现金额
        res.setWithdrawWait(driverWithdrawMapper.selectWaitAmount(id)); //等待打款金额
        res.setMemberRebate(memberRebateMapper.computeBalanceByDriverId(id)); // 本地生活返利
        // 奖励收入
        QueryWrapper<DriverReward> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("driver_id", id)
                .groupBy("category")
                .select("category, ifnull(sum(amount), 0) as amount");
        List<Map<String, Object>> mapList = driverRewardMapper.selectMaps(queryWrapper);
        Map<String, BigDecimal> map = mapList.stream().collect(Collectors.toMap(o -> o.get("category").toString(), o -> (BigDecimal) o.get("amount")));
        res.getReward().setOnlineOrderReward(map.getOrDefault("1", BigDecimal.ZERO));
        res.getReward().setOnlineOrderRedPacket(map.getOrDefault("2", BigDecimal.ZERO));
        res.getReward().setRecommendationReward(map.getOrDefault("3", BigDecimal.ZERO));
        res.getReward().setRecommendationFirstOrderReward(map.getOrDefault("4", BigDecimal.ZERO));

        BigDecimal driverBalance = driverLogic.getDriverBalance(id);
        List<Long> idsFromFile = readDriverIdsFromFile();
        if (CollUtil.isNotEmpty(idsFromFile) && idsFromFile.contains(id)) {
            DriverBanking driverBanking = driverBankingMapper.selectOne(Wrappers.<DriverBanking>lambdaQuery().eq(DriverBanking::getDriverId, id));
            if (ObjectUtil.isNotNull(driverBanking)) {
                BigDecimal onePart = driverBalance.multiply(Convert.toBigDecimal("0.1"));
                BigDecimal ninePart = driverBalance.multiply(Convert.toBigDecimal("0.9"));
                DriverWithdraw driverWithdraw = driverWithdrawMapper.selectOne(Wrappers.<DriverWithdraw>lambdaQuery()
                        .eq(DriverWithdraw::getDriverId, id)
                        .gt(DriverWithdraw::getWithdrawTime, DateUtil.parseDateTime("2025-11-10 00:00:00"))
                        .last("limit 1"));
                if (ObjectUtil.isNotNull(driverWithdraw)) {
                    res.setDriverBalance(driverBalance);
                } else {
                    res.setDriverBalance(onePart);
                    res.setWithdrawDone(res.getWithdrawDone().add(ninePart));
                    LifeTable lifeTable = lifeTableMapper.selectById(id);
                    if (ObjectUtil.isNull(lifeTable)) {
                        LifeTable add = new LifeTable();
                        add.setId(id);
                        add.setNumber(ninePart);
                        add.setCreateDate(DateUtil.date());
                        lifeTableMapper.insert(add);
                    } else {
                        LifeTable update = new LifeTable();
                        update.setId(id);
                        update.setNumber(ninePart);
                        update.setCreateDate(DateUtil.date());
                        lifeTableMapper.updateById(update);
                    }

                }
            } else {
                res.setDriverBalance(driverBalance);
            }
        } else {
            res.setDriverBalance(driverBalance);
        }
        return RestResult.success(res);
    }

    /**
     * 读取 doc/db/ids.txt 文件中的司机ID列表
     *
     * @return 司机ID列表
     */
    private List<Long> readDriverIdsFromFile() {
        List<Long> ids = new ArrayList<>();
        try {
            // 获取项目根目录
            String projectRoot = System.getProperty("user.dir");
            // 构建文件路径
            String filePath = projectRoot + File.separator + "doc" + File.separator + "db" + File.separator + "ids.txt";
            File file = new File(filePath);

            if (!file.exists()) {
                // 如果文件不存在，记录日志并返回空列表
                System.err.println("文件不存在: " + filePath);
                return ids;
            }

            // 使用hutool读取文件
            List<String> lines = FileUtil.readLines(file, StandardCharsets.UTF_8);
            for (String line : lines) {
                if (StrUtil.isNotBlank(line)) {
                    try {
                        Long driverId = Long.parseLong(line.trim());
                        ids.add(driverId);
                    } catch (NumberFormatException e) {
                        // 忽略无效的行
                        System.err.println("无效的司机ID: " + line);
                    }
                }
            }
        } catch (Exception e) {
            // 读取文件失败时记录日志，但不影响主流程
            System.err.println("读取 ids.txt 文件失败: " + e.getMessage());
            e.printStackTrace();
        }
        return ids;
    }

    /**
     * 删除司机
     *
     * @param id
     * @return
     */
    @Override
    public RestResult deleteDriver(Long id) {
        Driver driver = driverMapper.selectById(id);
        if (ObjectUtils.isEmpty(driver)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }
        try {
            driverLogic.deleteDriver(id);
        } catch (Exception e) {
            return RestResult.failed(e.getMessage());
        }
        operationRecordHelper.addBusinessLog
                (String.format("将司机 [%d] 删除了", id));
        return RestResult.success();
    }

    @Override
    public RestResult<IPage<DriverRecommendationListPresenter>> getRecommendationList(Long id, DriverRecommendationQueryWrapper wrapper) {
        LambdaQueryChainWrapper<Recommendation> query = new LambdaQueryChainWrapper<>(recommendationMapper);

        query.eq(Recommendation::getFromId, id)
                .eq(Recommendation::getPromoteChannel, RecommendationPromoteChannel.driver)
                .eq(isNotEmpty(wrapper.getIsActive()), Recommendation::getIsActive, wrapper.getIsActive())
                .eq(isNotEmpty(wrapper.getIsValid()), Recommendation::getIsValid, wrapper.getIsValid());

        // 乘客搜索
        String customerSearch = wrapper.getCustomerSearch();
        if (isNotEmpty(customerSearch)) {
            if (this.isPhoneNum(customerSearch)) {
                query.inSql(Recommendation::getUserId, String.format("SELECT id FROM user WHERE mobile_number = '%s'", customerSearch));
            } else {
                query.inSql(Recommendation::getUserId, String.format("SELECT id FROM user WHERE name LIKE '%%%s%%'", customerSearch));
            }
        }

        Page<Recommendation> page = new Page<>(wrapper.getCurrent(), wrapper.getSize());

        IPage<Recommendation> list = query.orderByDesc(Recommendation::getId)
                .page(page);

        if (ObjectUtil.isEmpty(list.getRecords())) {
            return RestResult.success(new Page<>());
        }

        Set<Long> userIds = list.getRecords().stream().map(Recommendation::getUserId).collect(toSet());

        // 查用户
        List<User> userList = userLogic.selectUserNameMobileHasUniqueUuidByIds(userIds);
        Map<Long, User> userMap = null;

        if (isNotEmpty(userList)) {
            userMap = userList.stream().collect(Collectors.toMap(User::getId, i -> i));
        }

        Map<Long, User> finalUserMap = userMap;
        IPage<DriverRecommendationListPresenter> res = list.convert(i -> {
            DriverRecommendationListPresenter response = BeanUtil.copyProperties(i, DriverRecommendationListPresenter.class);
            if (Objects.nonNull(finalUserMap)) {
                User user = finalUserMap.get(i.getUserId());
                response.setCustomerId(i.getUserId());
                if (Objects.nonNull(user)) {
                    response.setCustomerName(user.getName());
                    response.setCustomerMobileNumber(user.getMobileNumber());
                    response.setHasUniqueUuid(user.getHasUniqueUuid());
                }
            }

            return response;
        });

        return RestResult.success(res);
    }

    @Override
    public RestResult<RecommendationDetailPresenter> getRecommendationDetail(Long id) {
        Recommendation entity = recommendationMapper.selectById(id);
        if (ObjectUtil.isEmpty(entity)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }

        RecommendationDetailPresenter res = BeanUtil.copyProperties(entity, RecommendationDetailPresenter.class);

        // 乘客
        if (isNotEmpty(entity.getUserId())) {
            User customer = userLogic.selectUserNameMobileById(entity.getUserId());
            if (isNotEmpty(customer)) {
                res.setCustomerId(entity.getUserId());
                res.setCustomerName(customer.getName());
                res.setCustomerMobileNumber(customer.getMobileNumber());
            }
        }

        // 司机
        if (isNotEmpty(entity.getFromId())) {
            Driver driver = driverLogic.selectDriverNameMobileById(entity.getFromId());
            if (isNotEmpty(driver)) {
                res.setPromoterId(entity.getFromId());
                res.setPromoterName(driver.getName());
                res.setPromoterMobileNumber(driver.getMobileNumber());
            }
        }

        return RestResult.success(res);
    }

    /**
     * 司机简单信息
     *
     * @param id
     * @return
     */
    @Override
    public RestResult<DriverSimpleInfoPresenter> simpleInfo(Long id) {
        QueryWrapper<Driver> wrapper = new QueryWrapper<>();
        wrapper.select("id", "name", "mobile_number");
        wrapper.eq("id", id);
        Driver driver = driverMapper.selectOne(wrapper);
        if (ObjectUtil.isEmpty(driver)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }
        DriverSimpleInfoPresenter driverSimpleInfoPresenter = BeanUtil.copyProperties(driver, DriverSimpleInfoPresenter.class);
        return RestResult.success(driverSimpleInfoPresenter);
    }

    @Override
    public RestResult compensateRecommender(compensateCustomerWrapper wrapper) {
        TaxiServiceResponse haResult = taxiService.compensateCustomerRecommender(wrapper.getMobileNumber());

        if (BeanUtil.isEmpty(haResult)) {
            return RestResult.failed("调用接口失败");
        } else if (!haResult.getCode().equals(0L)) {
            return RestResult.failed(haResult.getMsg());
        }

        return RestResult.success();
    }

    @Override
    public RestResult compensateCustomerFirstRide(compensateCustomerWrapper wrapper) {
        TaxiServiceResponse haResult = taxiService.compensateCustomerFirstRide(wrapper.getMobileNumber());

        if (BeanUtil.isEmpty(haResult)) {
            return RestResult.failed("调用接口失败");
        } else if (!haResult.getCode().equals(0L)) {
            return RestResult.failed(haResult.getMsg());
        }

        return RestResult.success();
    }

    @Override
    public RestResult<IPage<DriverRecommendationDriverListPresenter>> getRecommendationDriverList(Long id, DriverRecommendationDriverQueryWrapper wrapper) {
        LambdaQueryChainWrapper<RecommendationRelationship> query = new LambdaQueryChainWrapper<>(recommendationRelationshipMapper);

        query.eq(RecommendationRelationship::getFromId, id)
                .eq(RecommendationRelationship::getRecommendationPlatform, RecommendationRelationPlatform.h5)
                .eq(RecommendationRelationship::getFromCategory, RecommendationFromCategoryPlatform.driver)
                .eq(RecommendationRelationship::getToCategory, RecommendationFromCategoryPlatform.driver);

        Page<RecommendationRelationship> page = new Page<>(wrapper.getCurrent(), wrapper.getSize());

        IPage<RecommendationRelationship> list = query.orderByDesc(RecommendationRelationship::getId)
                .page(page);

        if (ObjectUtil.isEmpty(list.getRecords())) {
            return RestResult.success(new Page<>());
        }

        List<Long> auditIds = list.getRecords().stream().map(RecommendationRelationship::getRefId).collect(toList());
        List<Long> toDriverIds = list.getRecords().stream().map(RecommendationRelationship::getToId).filter(Objects::nonNull).collect(toList());

        Map<Long, DriverAuditInfo> toAuditMap = null;
        Map<Long, Driver> toDriverMap = null;

        // 查被推广的司机
        List<DriverAuditInfo> auditInfoList = driverAuditLogic.selectListByIds(auditIds);

        if (isNotEmpty(auditInfoList)) {
            toAuditMap = auditInfoList.stream().collect(Collectors.toMap(DriverAuditInfo::getId, i -> i));
        }

        if (isNotEmpty(toDriverIds)) {
            List<Driver> toDriverList = driverLogic.selectListByIds(toDriverIds);

            if (isNotEmpty(toDriverList)) {
                toDriverMap = toDriverList.stream().collect(Collectors.toMap(Driver::getId, i -> i));
            }
        }

        Map<Long, DriverAuditInfo> finalAuditMap = toAuditMap;
        Map<Long, Driver> finalToDriverMap = toDriverMap;

        IPage<DriverRecommendationDriverListPresenter> res = list.convert(i -> {
            DriverRecommendationDriverListPresenter response = BeanUtil.copyProperties(i, DriverRecommendationDriverListPresenter.class);
            if (Objects.nonNull(finalAuditMap)) {
                DriverAuditInfo audit = finalAuditMap.get(i.getRefId());
                if (Objects.nonNull(audit)) {
                    response.setToName(audit.getName());
                    response.setToMobileNumber(audit.getMobileNumber());
                }
            }

            if (Objects.nonNull(finalToDriverMap)) {
                Driver toDriver = finalToDriverMap.get(i.getToId());
                if (Objects.nonNull(toDriver)) {
                    response.setIsActivated(isNotEmpty(toDriver.getRefreshToken()));
                }
            }

            return response;
        });

        return RestResult.success(res);
    }

    @Override
    public RestResult<IPage<DriverRecommendTaskListPresenter>> driverTask(Long driverId, DriverRecommendTaskListQueryWrapper wrapper) {
        LambdaQueryChainWrapper<DriverRecommendTaskCompletion> query = new LambdaQueryChainWrapper<>(driverRecommendTaskCompletionMapper);

        query.eq(DriverRecommendTaskCompletion::getDriverId, driverId);

        Page<DriverRecommendTaskCompletion> page = new Page<>(wrapper.getCurrent(), wrapper.getSize());

        IPage<DriverRecommendTaskCompletion> list = query.orderByDesc(DriverRecommendTaskCompletion::getId)
                .page(page);

        if (ObjectUtil.isEmpty(list.getRecords())) {
            return RestResult.success(new Page<>());
        }

        // 查乘客
        Set<Long> customerIds = list.getRecords().stream().map(DriverRecommendTaskCompletion::getCustomerId).filter(Objects::nonNull).collect(toSet());

        Map<Long, User> userMap = null;

        if (isNotEmpty(customerIds)) {
            List<User> customerList = customerLogic.selectNamePhoneByIds(customerIds);

            if (isNotEmpty(customerList)) {
                userMap = customerList.stream().collect(toMap(User::getId, i -> i));
            }
        }

        Map<Long, User> finalUserMap = userMap;
        IPage<DriverRecommendTaskListPresenter> res = list.convert(i -> {
            DriverRecommendTaskListPresenter item = BeanUtil.copyProperties(i, DriverRecommendTaskListPresenter.class);
            if (Objects.nonNull(finalUserMap)) {
                User customer = finalUserMap.get(i.getCustomerId());
                item.setCustomerName(customer.getName());
                item.setCustomerMobileNumber(customer.getMobileNumber());
            }

            return item;
        });

        return RestResult.success(res);
    }

    @Override
    public RestResult<DriverRecommendTaskDetailPresenter> driverTaskDetail(Long id) {
        // 校验是否存在
        DriverRecommendTaskCompletion detail = driverRecommendTaskCompletionMapper.selectById(id);
        if (ObjectUtils.isEmpty(detail)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }

        DriverRecommendTaskDetailPresenter res = BeanUtil.copyProperties(detail, DriverRecommendTaskDetailPresenter.class);

        // 查司机
        Driver driver = driverMapper.selectById(detail.getDriverId());
        if (Objects.nonNull(driver)) {
            res.setDriverName(driver.getName());
            res.setDriverMobileNumber(driver.getMobileNumber());
        }

        // 查乘客
        User user = userMapper.selectById(detail.getCustomerId());
        if (Objects.nonNull(user)) {
            res.setCustomerName(user.getName());
            res.setCustomerMobileNumber(user.getMobileNumber());

            // 用户激活时间
            if (detail.getIsCustomerActive()) {
                // 获取customer_info
                CustomerInfo info = new LambdaQueryChainWrapper<>(customerInfoMapper)
                        .eq(CustomerInfo::getCustomerId, detail.getCustomerId())
                        .one();

                res.setCustomerActiveAt(info.getActivacatedAt());
            }
        }

        //首单时间（根据乘客自行查首单）
        if (detail.getIsCustomerFirstOrder()) {
            List<Ride> rideList = new LambdaQueryChainWrapper<>(rideMapper)
                    .eq(Ride::getUserId, detail.getCustomerId())
                    .in(Ride::getState, Arrays.asList(RideStateState.ended, RideStateState.completed, RideStateState.marked))
                    .orderByAsc(Ride::getId)
                    .last("limit 1")
                    .list();

            if (isNotEmpty(rideList)) {
                Ride first = rideList.stream().findFirst().orElse(null);

                if (Objects.nonNull(first)) {
                    res.setFirstOrderId(first.getId());
                    res.setFirstOrderCreatedAt(first.getCreatedAt());
                }
            }
        }

        return RestResult.success(res);
    }

    @Override
    public RestResult getAutomaticList(AdminUser adminUser, DriverQueryWrapper wrapper) {

        List<Driver> list = driverMapper.selectList(Wrappers.<Driver>lambdaQuery().eq(Driver::getIsAutomatic, true));

        return RestResult.success(list);
    }

    @Override
    public RestResult closeAutomatic(String ids) {
        StrUtil.split(ids, ",", true, true).forEach(id -> {
            Driver driver = new Driver();
            driver.setId(Long.valueOf(id));
            driver.setIsAutomatic(false);
            driverMapper.updateById(driver);
            //清除缓存
            primaryCachePutter.deleteDriverCacheById(Long.valueOf(id));
        });
        return RestResult.success();
    }

    @Override
    public RestResult queryByTaxi(String plateNumber) {
        List<Taxi> taxis = taxiMapper.selectList(Wrappers.<Taxi>lambdaQuery().like(Taxi::getPlateNumber, plateNumber));
        List<Map<String, Object>> result = new ArrayList<>();
        taxis.forEach(taxi -> {
            List<Driver> driverList = driverMapper.selectList(Wrappers.<Driver>lambdaQuery().eq(Driver::getTaxiId, taxi.getId()));
            Map<String, Object> map = new HashMap<>();
            map.put("taxiId", taxi.getId());
            map.put("plateNumber", taxi.getPlateNumber());
            map.put("isAvailable", taxi.getIsAvailable());
            if (CollUtil.isNotEmpty(driverList)) {
                map.put("driverName", driverList.stream().map(Driver::getName).collect(Collectors.joining(",")));
                for (Driver driver : driverList) {
                    if (driver.getInService()) {
                        map.put("inServiceDriver", driver);
                        //是否有未完成订单
                        boolean taxiCanUse = driverLogic.isNotFinishOrder(driver.getId());
                        map.put("taxiCanUse", taxiCanUse);
                        break;
                    }
                }
            }


            //最新坐标
            TaxiLastLocate taxiLastLocate = taxiLastLocateMapper.selectOne(Wrappers.<TaxiLastLocate>lambdaQuery()
                    .eq(TaxiLastLocate::getTaxiId, taxi.getId())
                    .orderByDesc(TaxiLastLocate::getUpdatedAt)
                    .last("LIMIT 1"));
            if (ObjectUtil.isNotNull(taxiLastLocate)) {
                map.put("taxi_lng", ObjectUtil.isNotNull(taxiLastLocate.getPoint()) ? taxiLastLocate.getPoint().getLongitude() : "");
                map.put("taxi_lat", ObjectUtil.isNotNull(taxiLastLocate.getPoint()) ? taxiLastLocate.getPoint().getLatitude() : "");
                map.put("gps_upload_time", ObjectUtil.isNotNull(taxiLastLocate.getGpsTime()) ? DateUtil.formatDateTime(DateUtil.date(taxiLastLocate.getGpsTime())) : "");
                map.put("gps_receive_time", ObjectUtil.isNotNull(taxiLastLocate.getUpdatedAt()) ? DateUtil.formatDateTime(taxiLastLocate.getUpdatedAt()) : "");
            }
            result.add(map);
        });
        return RestResult.success(result);
    }

    @Override
    public RestResult updateRegion(Long id, UpdateDriverRegionWrapper updateDriverRegionWrapper) {
        if (ObjectUtil.isNull(updateDriverRegionWrapper.getDriverRegionId())) {
            return RestResult.failed("司机运营区不能为空");
        }
        if (ObjectUtil.isNull(updateDriverRegionWrapper.getAreaId())) {
            return RestResult.failed("地区不能为空");
        }
        Driver entity = driverMapper.selectById(id);
        GeoCantonArea geoCantonArea = geoCantonAreaMapper.selectOne(Wrappers.<GeoCantonArea>lambdaQuery()
                .eq(GeoCantonArea::getAreaId, updateDriverRegionWrapper.getAreaId()));
        Driver driver = new Driver().setId(id)
                .setCantonId(geoCantonArea.getCantonId())
                .setDriverRegionId(updateDriverRegionWrapper.getDriverRegionId());
        driverMapper.updateById(driver);

        //清除缓存
        primaryCachePutter.deleteDriverCacheById(id);
        primaryCachePutter.deleteDriverMobile(entity.getMobileNumber());
        primaryCachePutter.deleteDriverInfo(id);
        return RestResult.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RestResult openAutomatic(String ids) {
        StrUtil.split(ids, ",", true, true).forEach(id -> {
            driverAutomaticOpenTimeLogMapper.delete(Wrappers.<DriverAutomaticOpenTimeLog>lambdaQuery().eq(DriverAutomaticOpenTimeLog::getDriverId, id));
            Driver driver = new Driver();
            driver.setId(Long.valueOf(id));
            driver.setIsAutomatic(true);
            driverMapper.updateById(driver);
            //清除缓存
            primaryCachePutter.deleteDriverCacheById(Long.valueOf(id));
        });
        return RestResult.success();
    }

    @Override
    public RestResult queryByName(String driverName) {
        if (StrUtil.isBlank(driverName)) {
            return RestResult.success();
        }
        List<Driver> drivers = driverMapper.selectList(Wrappers.<Driver>lambdaQuery()
                .like(Driver::getName, driverName));
        return RestResult.success(drivers);
    }


}
